#ifndef CXSCHEDULER_H
#define CXSCHEDULER_H


#include <iostream>
#include <string>
#include <vector>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <mutex>
#include <fstream>
#include <algorithm>
#include <queue>
#include <map>
#include <thread>
#include <condition_variable>
#include <sqlite3.h>
#include <unordered_map>
#include <nlohmann/json.hpp>


typedef nlohmann::json JointJsonPack;
typedef std::string JointJsonPath;


#define TIME_BLOCK 0

enum TaskType {
    TASK_LOAD_UP,
    TASK_WELD_BASE_SCAN,
    TASK_ASSEMBLE_PART1,
    TASK_WELD_POINT1,
    TASK_ASSEMBLE_PART2,
    TASK_WELD_POINT2,
    TASK_WELD_FULL,
    TASK_LOAD_DOWN,
    TASK_PART_PICE
};

class CXScheduler;
extern std::mutex logMutex;
extern CXScheduler sch;



static std::string taskTypeToString(TaskType type) {
    switch (type) {
    case TASK_LOAD_UP:
        return "上料";
    case TASK_WELD_BASE_SCAN:
        return "底板扫描";
    case TASK_ASSEMBLE_PART1:
        return "拼装1";
    case TASK_WELD_POINT1:
        return "点焊1";
    case TASK_ASSEMBLE_PART2:
        return "拼装2";
    case TASK_WELD_POINT2:
        return "点焊2";
    case TASK_WELD_FULL:
        return "满焊";
    case TASK_LOAD_DOWN:
        return "下料";
    case TASK_PART_PICE:
        return "Link";
    default:
        return "Unknown";
    }
}

// 字符串转枚举类型的函数
static TaskType stringToTaskType(const std::string& str) {
    static const std::unordered_map<std::string, TaskType> stringToTaskMap = {
        {"上料", TASK_LOAD_UP},
        {"底板扫描", TASK_WELD_BASE_SCAN},
        {"拼装1", TASK_ASSEMBLE_PART1},
        {"点焊1", TASK_WELD_POINT1},
        {"拼装2", TASK_ASSEMBLE_PART2},
        {"点焊2", TASK_WELD_POINT2},
        {"满焊", TASK_WELD_FULL},
        {"下料", TASK_LOAD_DOWN},
        {"Link", TASK_PART_PICE}
    };

    auto it = stringToTaskMap.find(str);
    if (it != stringToTaskMap.end()) {
        return it->second;
    } else {
        std::cerr << "找不到对应的任务类型~ " << str << std::endl;
        std::exit(-100);
    }
}
// 任务类
struct Task {
    TaskType type;
    std::string station;
    std::string workpieceModel; // 新增工件名称
    int partID{-3}; // 仅用于装配和点焊任务
    float duration{0};
    int wrlid;

    JointJsonPath joint_json;
    JointJsonPath link_json;

    JointJsonPath db;

    std::map<int,JointJsonPath> link_part_json;

    // 构造函数
    Task(TaskType t, const std::string& s, const std::string& wm, float d,JointJsonPath json,
         int w = -1, int p = -1,JointJsonPath lk = "",JointJsonPath _db = "");
};


typedef int TimeUnit;

class LOGGER{
public:
    LOGGER(std::string logFileName){
        // 打开日志文件
        logFile.open(logFileName, std::ios::out);
        if (!logFile.is_open()) {
            std::cerr << "Failed to open " << logFileName << " for writing." << std::endl;
            exit(1);
        }

        // 写入CSV表头
        logFile << "RobotType,Station,StartTime,EndTime,Duration,工件名,wrlID,PartID,轴数据,DB\n";
    }

    void Close(){
        if (logFile.is_open()) {
            logFile.close();
        }
    }

    ~LOGGER(){
        if (logFile.is_open()) {
            logFile.close();
        }
    }
    // CSV日志文件
    std::ofstream logFile;
    void logTask(const Task &task, const TimeUnit& start_time,
                        const TimeUnit& end_time) {
        // 写入日志文件
        std::lock_guard<std::mutex> guard(logMutex);

        std::string dd = taskTypeToString(task.type);
        logFile << dd << "," << task.station << ","
                << std::to_string(start_time) << "," << std::to_string(end_time)  << ","
                << task.duration << "," << task.workpieceModel << ","
                << task.wrlid << ","
                << task.partID << ","
                << task.joint_json<< "," << task.db << "\n";
    }

    void logTaskNoThisJoint(const Task &task, const TimeUnit& start_time,
                        const TimeUnit& end_time,const JointJsonPath & jsp) {
        // 写入日志文件
        std::lock_guard<std::mutex> guard(logMutex);

        std::string dd = taskTypeToString(TASK_PART_PICE);
        logFile << dd << "," << task.station << ","
                << std::to_string(start_time) << "," << std::to_string(end_time)  << ","
                << task.duration << "," << task.workpieceModel << ","
                << task.wrlid << ","
                << task.partID << ","
                << jsp<< "," << task.db << "\n";
    }

    void logTaskPart(const Task &task, const TimeUnit& start_time,
                        const TimeUnit& end_time,const JointJsonPath & jsp,int partID = -1) {
        // 写入日志文件
        std::lock_guard<std::mutex> guard(logMutex);

        std::string dd = taskTypeToString(TASK_PART_PICE);
        logFile << dd << "," << task.station << ","
                << std::to_string(start_time) << "," << std::to_string(end_time)  << ","
                << task.duration << "," << task.workpieceModel << ","
                << task.wrlid << ","
                << partID << ","
                << jsp<< "," << task.db << "\n";
    }
};

extern LOGGER logger;


// 机器人基类
class Robot {
public:
    TimeUnit available_time;

    Robot() : available_time(0) {}

    virtual ~Robot() {}

    static std::string Time2Str(const TimeUnit &p){
            return std::to_string(p);
    }
};

// 加载机器人类
class RobotLoader : public Robot {
public:
    void performTask(const Task& task) {
        // 确定任务开始时间
        auto start_time = available_time;
        auto end_time = start_time + task.duration;

        logger.logTask(task, start_time, end_time);

        // 更新可用时间
        available_time = end_time;
    }
};

// 卸载机器人类
class RobotUnloader : public Robot {
public:
    std::map<std::string,TimeUnit> time_start;
    std::map<std::string,bool> unloaderStates; // 下料状态
    std::map<std::string,TimeUnit> unloaderTimes;
    void performTask(const Task& task) {
        // 确定任务开始时间
        auto start_time = available_time;
        auto end_time = start_time + task.duration;

        logger.logTask(task, start_time, end_time);

        // 更新可用时间
        available_time = end_time;
    }
};

// 装配机器人类
class RobotAssemble : public Robot {
public:
    // mutex to ensure only one station is served at a time
    std::mutex assembleMutex;

    std::map<std::string,TimeUnit> sTime;
    std::map<std::string,TimeUnit> eTime;

    std::map<std::string,TimeUnit> vTime;

    void performTask(const Task& task) {
        // 申请装配机器人的资源
        std::unique_lock<std::mutex> lock(assembleMutex);

        // 确定任务开始时间
        auto start_time = available_time;
        auto end_time = start_time + task.duration;

        logger.logTask(task, start_time, end_time);

        // 更新装配机器人的可用时间
        available_time = end_time;
    }
};

// 焊接机器人类
class WeldRobot : public Robot {
public:
    // 焊接机器人可以同时工作，因此不需要额外的mutex
    void performTask(const Task& task) {
        // 确定任务开始时间
        auto start_time = available_time;
        auto end_time = start_time + task.duration;

        logger.logTask(task, start_time, end_time);

        // 更新焊接机器人的可用时间
        available_time = end_time;
    }
};


struct PartInfos{
    int partID;
    int wrlID;

    bool operator<(const PartInfos& other) const {
        return partID < other.partID;  // 从0到1排序
    }

    std::string GetPartName();

    TimeUnit partAssTimes1 = TIME_BLOCK; // 每个零件的装配时间
    TimeUnit partTimes1 = TIME_BLOCK; // 每个零件的点焊时间
    TimeUnit partAssTimes2 = TIME_BLOCK; // 每个零件的装配2时间
    TimeUnit partTimes2 = TIME_BLOCK; // 每个零件的点焊2时间
    bool partsSpotWelded; // 跟踪每个零件是否完成点焊

    int chainID;
    int pri_partID;     /** DB中唯一 **/


    JointJsonPath js_Ass1;
    JointJsonPath js_t1;
    JointJsonPath js_Ass2;
    JointJsonPath js_t2;

    JointJsonPath js_part1;
    JointJsonPath js_part2;
};

// 工位类
struct OneWrlInfo {
    std::string name;       // 工作站名称
    std::string workpieceModel; // 工件名
    int wrlid;

    // 重载 < 运算符，用于定义比较规则
    bool operator<(const OneWrlInfo& other) const {
        return wrlid < other.wrlid;  // 从0到1排序
    }

    int currentPart; // 当前处理的零件ID
    int totalParts; // 总零件数

    TimeUnit fullWeldTime = TIME_BLOCK;   /* 满焊时间 */
    TimeUnit unLoaderTime = TIME_BLOCK;
    TimeUnit LoaderTime = TIME_BLOCK;
    TimeUnit BGSTime = TIME_BLOCK;        /* 底板扫描时间 */
    TimeUnit assTime = TIME_BLOCK;

    std::vector<PartInfos> parts;   /* 存储零件 */

    bool fullWeldCompleted;
    bool baseScanCompleted; // 标记底板扫描是否完成
    bool isWorking;
    TimeUnit baseScanCompletionTime; // 底板扫描任务的完成时间
    TimeUnit nextAvailableTime; // 下一个可用时间

    /** 从焊接轨迹中提取满焊和点焊的轨迹 **/
    void CreateWeldJoint(const std::string &json);

    void CreateScanJoint(const std::string &json);
    void CreateUpJoint(const std::string &json);
    void CreateDownJoint(const std::string &json);
    void SortParts(){ std::sort(parts.begin(),parts.end()); }

    std::string j_up;
    std::string j_up_DB;
    std::string j_down;
    std::string j_down_DB;
    std::string j_scan;
    std::string j_scan_DB;
    std::string j_full;
    std::string j_full_DB;

    std::string j_up_link;
    std::string j_down_link;

    std::map<int,std::string> j_down_link_part;

    OneWrlInfo(const std::string& n, const std::string& wm, int i)
        : name(n), workpieceModel(wm), wrlid(i), isWorking(false),
        fullWeldCompleted(false), baseScanCompleted(false), currentPart(0) {

         nextAvailableTime = 0; // 初始化为当前时间
    }
};

class CXScheduler
{
public:
    CXScheduler();

    void OpenDB(const std::string &d);

    void CloseDB();

    int GetChainByID(int wrlID,int partID);

    int GetChainByStation(int stID,TaskType tp,int chain_ori);

    int moniCount{0};
    int ch1Real;
    int ch2Real;
    int chAssReal;
    int chUp;
    int chDown;
private:
    sqlite3* db;
};

// 调度器类
class Scheduler {
public:
    // 机器人实例
    RobotLoader loader;
    RobotUnloader unloader;
    RobotAssemble assembler;
    std::map<std::string,WeldRobot> weldRobots; // 每个工位一个焊接机器人


    TimeUnit GetWRLAss(const std::string &name);

    // 工位列表
    std::vector<OneWrlInfo> wrls;
    // 任务列表
    std::vector<Task> tasks;

    // 创建所有任务
    void createAllTasks();
    void scheduleAllTasks();


    Scheduler(const std::vector<OneWrlInfo> &sts);
    ~Scheduler();
private:
    // 获取工位索引
    size_t getOneWrlInfoIndex(const std::string& wrl);
    void scheduleLoadUp(const Task &task);
    void scheduleWeldBaseScan(const Task &task);
    void scheduleAssemblyPhase1(const Task &task);
    void scheduleSpotWeldPhase1(const Task &task);
    void scheduleAssemblyPhase2(const Task &task);
    void scheduleSpotWeldPhase2(const Task &task);
    void scheduleWeldFull(const Task &task);
    void scheduleLoadDown(const Task &task);
    bool isBaseScanCompleted(const std::string &wrlName);
};



#endif // CXSCHEDULER_H
